//
// Created by mmuee on 2024/5/15.
//

#ifndef YWZM_FUNCTRAITS_HPP
#define YWZM_FUNCTRAITS_HPP

#include "ConstDefine.hpp"

NS_UTILS_BEGIN
template<typename Class, typename ReturnType, typename... Args>
struct function_traits_defs
{
    static constexpr size_t arity = sizeof...(Args);
    using clazz = Class;
    using result_type = ReturnType;
    using argument_types = std::tuple<Args...>;
};

template<typename T>
struct function_traits_impl;

template<typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(Args...)> : function_traits_defs<void, ReturnType, Args...>
{
};

template<typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (*)(Args...)> : function_traits_defs<void, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...)>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) const>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) const&>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) const&&>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) volatile>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) volatile&>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType>
struct function_traits_impl<ReturnType(ClassType::*)> : function_traits_defs<ClassType, ReturnType>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) volatile&&>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) const volatile>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) const volatile&>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType (ClassType::*)(Args...) const volatile&&>
    : function_traits_defs<ClassType, ReturnType, Args...>
{
};

template<typename T, typename V = void>
struct function_traits : function_traits_impl<T>
{
};

template<typename T>
struct function_traits<T, decltype((void)&T::operator())>
    : function_traits_impl<decltype(&T::operator())>
{
};

template<size_t... Indices>
struct indices
{
    using next = indices<Indices..., sizeof...(Indices)>;
};
template<size_t N>
struct build_indices
{
    using type = typename build_indices<N - 1>::type::next;
};
template<>
struct build_indices<0>
{
    using type = indices<>;
};
template<size_t N>
using BuildIndices = typename build_indices<N>::type;
NS_UTILS_END

#endif //YWZM_FUNCTRAITS_HPP
